package com.lry.rpc.starter.extend;

import com.lry.rpc.starter.annotation.RpcComponentScan;
import com.lry.rpc.starter.annotation.RpcService;
import com.lry.rpc.starter.util.RpcBeanUtils;
import com.lry.rpc.starter.util.ScannerUtil;
import com.lry.util.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;

import java.util.HashSet;
import java.util.Set;

@Slf4j
public class RpcComponentScanRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(RpcComponentScan.class.getName()));
        String[] basePackages = attributes.getStringArray("basePackages");
        Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
        Set<Class<?>> classSet = getClassSet(basePackages,basePackageClasses);

        this.registerServiceAnnotationBeanPostProcessor(classSet, registry);
        RpcBeanUtils.registerCommonBeans(registry);
    }

    private void registerServiceAnnotationBeanPostProcessor(Set<Class<?>> classSet, BeanDefinitionRegistry registry) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
        builder.addConstructorArgValue(classSet);
        builder.setRole(2);
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
    }

    private Set<Class<?>> getClassSet(String[] basePackages,Class<?>[] basePackageClasses){
        Set<Class<?>> allSet = new HashSet<>();
        for (String basePackage : basePackages) {
            Set<Class<?>> classSet = ScannerUtil.scanAnnotation(basePackage, RpcService.class);
            allSet.addAll(classSet);
        }

        for (Class<?> basePackageClass : basePackageClasses) {
            if(basePackageClass.isAnnotationPresent(RpcService.class)){
                allSet.add(basePackageClass);
            }
        }
        return allSet;
    }
}
